﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Documents;
using System.ComponentModel;
using System.Windows.Controls;
using System.Xml;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using SHomeWorkshop.LunarTools;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Imaging;
using System.IO;
using Microsoft.Win32;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept;
using System.Diagnostics;
using System.Threading;
using System.IO.MemoryMappedFiles;

namespace SHomeWorkshop.LunarMind
{
    public class PictureBox : AdornerDecorator, INotifyPropertyChanged
    {
        public PictureBox(MainWindow editor, Title masterTitle)
        {
            this.editor = editor;
            this.masterTitle = masterTitle;
            this.masterTitleID = masterTitle.ID;

            this.connectLine.Stroke = this.borderColor;
            this.connectLine.StrokeThickness = 2.4;
            this.connectLine.StrokeDashArray = dashArray;

            this.mainImage.Cursor = Cursors.SizeAll;

            this.baseBorder.PreviewMouseRightButtonUp += new MouseButtonEventHandler(baseBorder_PreviewMouseRightButtonUp);
            this.baseBorder.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(baseBorder_PreviewMouseLeftButtonDown);

            this.Child = this.baseBorder;
            this.baseBorder.Child = this.baseViewBox;
            this.baseViewBox.Child = this.mainImage;

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.baseBorder);

            this.borderAdorner = new Adorners.PictureBoxBorderAdorner(this.baseBorder, this);
            adornerLayer.Add(this.borderAdorner);
        }

        private Border baseBorder = new Border() { Background = Brushes.Transparent, };

        private Viewbox baseViewBox = new Viewbox();

        static void miLoadImage_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox != null)
                Globals.MainWindow.SelectedPictureBox.LoadImageFromFile();
        }

        static void miIconMode_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null) return;
            var pictureBox = Globals.MainWindow.SelectedPictureBox;

            if (pictureBox.mode == ImageMode.Icon) return;

            ModifingItem mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框呈现模式为：中等图标"
            };

            Action actMode = new Action(pictureBox.ID, -1, pictureBox.GetType().Name, "Mode",
                pictureBox.Mode.ToString(), ImageMode.Icon.ToString());
            pictureBox.Mode = ImageMode.Icon;
            mi.Add(actMode);

            if (mi.ModifiedPropertyAndValues.Count > 0)
            {
                Globals.MainWindow.Do(mi);
                Globals.MainWindow.IsModified = true;
                //Globals.MainWindow.RefreshTitleAndLinesLocation();//无必要
            }
        }

        static void miDefaultMode_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null) return;
            var pictureBox = Globals.MainWindow.SelectedPictureBox;

            if (pictureBox.mode == ImageMode.Default) return;

            ModifingItem mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框呈现模式为：默认"
            };

            Action actMode = new Action(pictureBox.ID, -1, pictureBox.GetType().Name, "Mode",
                pictureBox.Mode.ToString(), ImageMode.Default.ToString());
            pictureBox.Mode = ImageMode.Default;
            mi.Add(actMode);

            if (mi.ModifiedPropertyAndValues.Count > 0)
            {
                Globals.MainWindow.Do(mi);
                Globals.MainWindow.IsModified = true;
                //Globals.MainWindow.RefreshTitleAndLinesLocation();//无必要
            }
        }

        private static MenuItem miDefaultMode;

        private static MenuItem miSmallIconMode;

        private static MenuItem miMediumIconMode;

        private static MenuItem miLargeIconMode;

        private static MenuItem miSuperlargeIconMode;

        void baseBorder_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //容易引起误解，还是取消的好，强迫用户从右键菜单进行操作更不会让人迷惑。
            //if (e.ClickCount == 2)
            //{
            //    switch (this.mode)
            //    {
            //        case ImageMode.SmallIcon:
            //            {
            //                this.PresentateImage();
            //                break;
            //            }
            //        default:
            //            {
            //                LoadImageFromFile();
            //                break;
            //            }
            //    }
            //    e.Handled = true;
            //}
            //else
            //{
            this.SelectOnlySelf();

            //准备拖动。
            editor.isDraggingPictureBox = true;
            Point pt = e.GetPosition(this);
            editor.SetPictureBoxDraggingSize(pt);

            e.Handled = true;
            //}
        }

        public TitleImage.ImageType ContentType
        {
            get
            {
                if (this.baseViewBox.Child == this.mainImage)
                    return TitleImage.ImageType.BitmapImage;
                else return TitleImage.ImageType.XamlElement;
            }
        }

        public void PresentateImage()
        {
            ImagePresentationWindow ipw = new ImagePresentationWindow() { Owner = Globals.MainWindow, };
            ipw.backgroundRect.Fill = Globals.MainWindow.mainCanvas.Background;

            if (this.ContentType == TitleImage.ImageType.BitmapImage)
            {
                ipw.mainImage.Source = this.mainImage.Source;

                BitmapImage bimg = this.mainImage.Source as BitmapImage;
                ipw.mainImage.Width = bimg.PixelWidth;
                ipw.mainImage.Height = bimg.PixelHeight;

                if (ipw.baseViewBox.Child != ipw.mainImage) ipw.baseViewBox.Child = ipw.mainImage;
            }
            else if (this.ContentType == TitleImage.ImageType.XamlElement)
            {
                PageEditorReader per = new PageEditorReader();
                var conceptNode = this.xmlData.SelectSingleNode(XmlTags.LunarConceptTag);
                per.XmlData = conceptNode.SelectSingleNode(XmlTags.PageTag);
                //per.Build();//设置XmlData属性值时会自动调用。

                ipw.baseViewBox.Child = per;
            }

            ipw.tbTitleText.Text = this.Title;
            ipw.RefreshImageTitleText();

            ipw.ShowDialog();
        }

        private string title = string.Empty;

        public string Title
        {
            get { return this.title; }
            set
            {
                this.title = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("Title", value);
                }
            }
        }

        void baseBorder_PreviewMouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            s_ContextMenu.IsOpen = true;
            e.Handled = true;
        }

        static void cmiHideConnectLine_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null)
            {
                MessageBox.Show("请先选中一个“图片框”！", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedPictureBox.MasterTitle == null ||
                Globals.MainWindow.SelectedPictureBox.MasterTitle != Globals.MainWindow.RootTitle)
            {
                MessageBox.Show("　　只有中心标题（根标题）引出的图片框才支持用户自定义连接线！" +
                    "其它标题引出的图片框总是显示连接线的。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedPictureBox.HideConnectLine == true) return;

            PictureBox curPb = Globals.MainWindow.SelectedPictureBox;

            ModifingItem mi = new ModifingItem() { ModifingName = "设置是否显示连接线" };

            Action actHideCommectLine = new Action(curPb.ID, -1, curPb.GetType().Name, "HideConnectLine",
                curPb.HideConnectLine.ToString(), true.ToString());

            curPb.HideConnectLine = true;

            mi.Add(actHideCommectLine);

            Globals.MainWindow.Do(mi);
            Globals.MainWindow.IsModified = true;
        }

        static void cmiShowConnectLine_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null)
            {
                MessageBox.Show("请先选中一个“图片框”！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedPictureBox.MasterTitle == null ||
                Globals.MainWindow.SelectedPictureBox.MasterTitle != Globals.MainWindow.RootTitle)
            {
                MessageBox.Show("　　只有中心标题（根标题）引出的图片框才支持用户自定义连接线！" +
                    "非中心标题（根标题）引出的图片框总是显示连接线的。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedPictureBox.HideConnectLine == false) return;

            PictureBox curPb = Globals.MainWindow.SelectedPictureBox;

            ModifingItem mi = new ModifingItem() { ModifingName = "设置是否显示连接线" };

            Action actHideCommectLine = new Action(curPb.ID, -1, curPb.GetType().Name, "HideConnectLine",
                curPb.HideConnectLine.ToString(), false.ToString());

            curPb.HideConnectLine = false;

            mi.Add(actHideCommectLine);

            Globals.MainWindow.Do(mi);
            Globals.MainWindow.IsModified = true;
        }

        public static DoubleCollection dashArray = new DoubleCollection() { 1, 1 };

        private Line connectLine = new Line();

        public System.Windows.Shapes.Line ConnectLine
        {
            get { return connectLine; }
        }

        private string id;

        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        public void RebuildANewID()
        {
            id = Guid.NewGuid().ToString();
            if (this.xmlData != null)
            {
                this.xmlData.SetAttribute("ID", id);
            }
        }

        private ImageMode mode = ImageMode.Default;

        public ImageMode Mode
        {
            get { return this.mode; }
            set
            {
                this.mode = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("Mode", this.mode.ToString());
                }

                this.RefreshMode();
                this.RefreshConnectLine();
            }
        }

        private void RefreshMode()
        {
            Size size = this.baseViewBox.Child.RenderSize;
            if (size.Width <= 0) size.Width = 32;
            if (size.Height <= 0) size.Height = 32;

            switch (this.mode)
            {
                case ImageMode.SmallIcon:
                    {
                        if (size.Width > size.Height)
                        {
                            this.baseViewBox.Width = 48;
                            this.baseViewBox.Height = 48 * (size.Height / size.Width);
                        }
                        else
                        {
                            this.baseViewBox.Height = 48;
                            this.baseViewBox.Width = 48 * (size.Width / size.Height);
                        }
                        break;
                    }
                case ImageMode.Icon:
                    {
                        if (size.Width > size.Height)
                        {
                            this.baseViewBox.Width = 96;
                            this.baseViewBox.Height = 96 * (size.Height / size.Width);
                        }
                        else
                        {
                            this.baseViewBox.Height = 96;
                            this.baseViewBox.Width = 96 * (size.Width / size.Height);
                        }
                        break;
                    }
                case ImageMode.LargeIcon:
                    {
                        if (size.Width > size.Height)
                        {
                            this.baseViewBox.Width = 192;
                            this.baseViewBox.Height = 192 * (size.Height / size.Width);
                        }
                        else
                        {
                            this.baseViewBox.Height = 192;
                            this.baseViewBox.Width = 192 * (size.Width / size.Height);
                        }
                        break;
                    }
                case ImageMode.SuperLargeIcon:
                    {
                        if (size.Width > size.Height)
                        {
                            this.baseViewBox.Width = 384;
                            this.baseViewBox.Height = 384 * (size.Height / size.Width);
                        }
                        else
                        {
                            this.baseViewBox.Height = 384;
                            this.baseViewBox.Width = 384 * (size.Width / size.Height);
                        }
                        break;
                    }
                default:
                    {
                        this.baseViewBox.Width = this.baseViewBox.Height = double.NaN;

                        //BitmapImage srcBitmpaImage = mainImage.Source as BitmapImage;
                        //if (mainImage != null && srcBitmpaImage != null)
                        //{
                        //    mainImage.Width = srcBitmpaImage.PixelWidth;
                        //    mainImage.Height = srcBitmpaImage.PixelHeight;
                        //}
                        break;
                    }
            }
        }

        private LineDashType.DashType lineDash = LineDashType.DashType.Dot;

        public LineDashType.DashType LineDash
        {
            get { return lineDash; }
            set
            {
                lineDash = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("LineDash", lineDash.ToString());
                }

                RefreshDashType();
            }
        }

        private void RefreshDashType()
        {
            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.Solid:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.solidCollection; break;
                    }
                default:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(object sender,
           PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(sender, e);
            }
        }

        /// <summary>
        /// 会重绘边框。
        /// </summary>
        public void RefreshLoaction()
        {
            if (MasterTitle == null)
            {
                this.Visibility = Visibility.Hidden;
                this.ConnectLine.Visibility = Visibility.Hidden;
                return;
            }
            else
            {
                if (MasterTitle.BeCollapsed)
                {
                    this.Visibility = Visibility.Hidden;
                    this.ConnectLine.Visibility = Visibility.Hidden;
                    return;
                }
                else
                {
                    this.Visibility = Visibility.Visible;

                    if (hideConnectLine)
                    {
                        this.ConnectLine.Visibility = Visibility.Hidden;
                    }
                    else
                    {
                        this.connectLine.Visibility = Visibility.Visible;
                    }
                }
            }

            if (this.masterTitle == editor.RootTitle)//从根标题引出的备注文本块固定位置。
            {
                Canvas.SetLeft(this, location.X);
                Canvas.SetTop(this, location.Y);
                RefreshConnectLine();
                return;
            }

            Rect masterRect = new Rect(MasterTitle.LeftTop.X, MasterTitle.LeftTop.Y,
                MasterTitle.ActualWidth, MasterTitle.ActualHeight);

            Point masterCenter = new Point(masterRect.Left + masterRect.Width / 2, masterRect.Top + masterRect.Height / 2);

            Point newLeftTop = new Point(masterCenter.X + location.X +
                (MasterTitle.Direction == TitleDirection.Right ? MasterTitle.IndentWidth : -MasterTitle.IndentWidth),
                masterCenter.Y + location.Y);

            Canvas.SetLeft(this, newLeftTop.X);
            Canvas.SetTop(this, newLeftTop.Y);

            this.borderAdorner.InvalidateVisual();

            this.InvalidateArrange();
            this.UpdateLayout();

            RefreshConnectLine();
        }

        private double rotateAngle = 0;

        public double RotateAngle
        {
            get { return rotateAngle; }
            set
            {
                if (value > 180)
                {
                    rotateAngle = 180;
                }
                else if (value < -180)
                {
                    rotateAngle = -180;
                }
                else
                {
                    rotateAngle = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("RotateAngle", rotateAngle.ToString());
                }

                RefreshRotateAngle();
            }
        }

        private static readonly Point defRenderCenter = new Point(0.5, 0.5);
        private static readonly RotateTransform defRotateTransform = new RotateTransform(0);

        private void RefreshRotateAngle()
        {
            if (this.RenderTransformOrigin != defRenderCenter)
            {
                this.RenderTransformOrigin = defRenderCenter;
            }

            if (rotateAngle == 0)
            {
                this.RenderTransform = defRotateTransform;
            }
            else
            {
                this.RenderTransform = new RotateTransform(rotateAngle);
            }
        }

        private bool hideConnectLine = false;

        /// <summary>
        /// 隐藏连接线。默认为false（显示）。
        /// </summary>
        public bool HideConnectLine
        {
            get { return hideConnectLine; }
            set
            {
                hideConnectLine = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("HideConnectLine", value.ToString());
                }
                RefreshConnectLine();
            }
        }

        public void RefreshConnectLine()
        {
            if (this.masterTitle != null && this.masterTitle == editor.RootTitle)
            {
                if (this.hideConnectLine)
                {
                    if (connectLine.Visibility != Visibility.Hidden)
                    {
                        connectLine.Visibility = Visibility.Hidden;
                    }
                    return;
                }
                else
                {
                    if (connectLine.Visibility != Visibility.Visible)
                    {
                        connectLine.Visibility = Visibility.Visible;
                    }
                }
            }
            else
            {
                if (this.connectLine.Visibility != Visibility.Visible)//不是从根标题引出的图片框总是显示连接线。
                {
                    this.connectLine.Visibility = Visibility.Visible;
                }
            }

            mainImage.InvalidateArrange();
            mainImage.UpdateLayout();

            if (MasterTitle == null || MasterTitle.ActualHeight <= 0 || MasterTitle.ActualWidth <= 0) return;

            Rect masterRect = new Rect(
                MasterTitle.LeftTop.X + MasterTitle.MainBorder.Margin.Left +
                (MasterTitle.Direction == TitleDirection.Right ? MasterTitle.IndentWidth : -MasterTitle.IndentWidth),
                MasterTitle.LeftTop.Y + MasterTitle.MainBorder.Margin.Top,
                MasterTitle.ActualWidth - MasterTitle.MainBorder.Margin.Left - MasterTitle.MainBorder.Margin.Right,
                MasterTitle.ActualHeight - MasterTitle.MainBorder.Margin.Top - MasterTitle.MainBorder.Margin.Bottom
                );

            Point masterCenter = new Point(masterRect.Left + masterRect.Width / 2, masterRect.Top + masterRect.Height / 2);
            Point newLeftTop = new Point(Canvas.GetLeft(this), Canvas.GetTop(this));

            Rect outBorderRect = new Rect(newLeftTop.X - 10, newLeftTop.Y - 10, this.ActualWidth + 20, this.ActualHeight + 20);

            if (outBorderRect.IntersectsWith(masterRect))
            {
                connectLine.Visibility = Visibility.Hidden;
            }
            else
            {
                PointToRect.ArrowPoints aptMasterTitle = PointToRect.GetCrossPointToRect(masterRect,
                    new Point(outBorderRect.Left + outBorderRect.Width / 2, outBorderRect.Top + outBorderRect.Height / 2));

                PointToRect.ArrowPoints aptPictureBox = PointToRect.GetCrossPointToRect(outBorderRect, masterCenter);

                connectLine.X1 = aptPictureBox.Top.X; connectLine.Y1 = aptPictureBox.Top.Y;
                connectLine.X2 = aptMasterTitle.Top.X; connectLine.Y2 = aptMasterTitle.Top.Y;

                connectLine.Visibility = Visibility.Visible;
            }
        }

        private bool isSelected = false;

        public bool IsSelected
        {
            get { return isSelected; }
            set
            {
                isSelected = value;
                this.borderAdorner.InvalidateVisual();//选取框、装饰框由同一个装饰器实现。
            }
        }

        public void SelectOnlySelf()
        {
            if (editor == null) return;

            if (editor.SelectedRelation != null) editor.SelectedRelation = null;
            if (editor.SelectedTitleImage != null) editor.SelectedTitleImage = null;
            if (editor.SelectedTitlesList.Count > 0) editor.ClearAllFromSelectedTitleList();

            editor.SelectedPictureBox = this;
            this.IsSelected = true;
        }

        private Adorners.PictureBoxBorderAdorner borderAdorner;

        private Image mainImage = new Image();

        public Image MainImage
        {
            get { return mainImage; }
        }


        void mainImage_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //会清除所有对标题的选取。
            this.IsSelected = true;

            //这个属性会执行清除选取状态的操作。
            editor.SelectedPictureBox = this;

            e.Handled = true;
        }

        private XmlNode xmlData;

        public XmlNode XmlData
        {
            get { return xmlData; }
            set
            {
                xmlData = value;
                BuildPictureBox();
            }
        }

        private static ContextMenu s_ContextMenu;

        public static ContextMenu S_ContextMenu
        {
            get { return PictureBox.s_ContextMenu; }
        }

        private static MenuItem cmiShowConnectLine;
        private static MenuItem cmiHideConnectLine;

        private static MenuItem cmiDot;
        private static MenuItem cmiDash;
        private static MenuItem cmiDashDot;
        private static MenuItem cmiDashDotDot;
        private static MenuItem cmiSolid;

        public static void ShowContextMenu()
        {
            if (s_ContextMenu != null) s_ContextMenu.IsOpen = true;
        }

        static PictureBox()
        {
            s_ContextMenu = new ContextMenu();
            s_ContextMenu.Opened += new RoutedEventHandler(contextMenu_Opened);

            MenuItem miLoadImage = new MenuItem() { Header = "载入位图文件(_L)", };
            miLoadImage.Click += miLoadImage_Click;
            s_ContextMenu.Items.Add(miLoadImage);

            MenuItem miImageTitle = new MenuItem() { Header = "设置标题文本(_T)", };
            miImageTitle.Click += miImageTitle_Click;
            s_ContextMenu.Items.Add(miImageTitle);

            s_ContextMenu.Items.Add(new Separator());

            MenuItem miPresentateImage = new MenuItem() { Header = "查看图像(_P)", InputGestureText = "F6", };
            miPresentateImage.Click += miPresentateImage_Click;
            s_ContextMenu.Items.Add(miPresentateImage);

            s_ContextMenu.Items.Add(new Separator());

            miDefaultMode = new MenuItem() { Header = "原始尺寸(_O)", IsChecked = true, };
            miDefaultMode.Click += miDefaultMode_Click;
            s_ContextMenu.Items.Add(miDefaultMode);

            miSmallIconMode = new MenuItem() { Header = "小图标(_S)", IsChecked = false, };
            miSmallIconMode.Click += MiSmallIcon_Click;
            s_ContextMenu.Items.Add(miSmallIconMode);

            miMediumIconMode = new MenuItem() { Header = "中等图标(_M)", IsChecked = false, };
            miMediumIconMode.Click += miIconMode_Click;
            s_ContextMenu.Items.Add(miMediumIconMode);

            miLargeIconMode = new MenuItem() { Header = "大图标(_I)", IsChecked = false, };
            miLargeIconMode.Click += MiLargeIcon_Click;
            s_ContextMenu.Items.Add(miLargeIconMode);

            miSuperlargeIconMode = new MenuItem() { Header = "特大图标(_S)", IsChecked = false, };
            miSuperlargeIconMode.Click += MiSuperlargeIcon_Click;
            s_ContextMenu.Items.Add(miSuperlargeIconMode);

            s_ContextMenu.Items.Add(new Separator());

            cmiShowConnectLine = new MenuItem() { Header = "显示连接线(_S)", Height = 20 };
            cmiShowConnectLine.Click += new RoutedEventHandler(cmiShowConnectLine_Click);

            cmiHideConnectLine = new MenuItem() { Header = "隐藏连接线(_H)", Height = 20 };
            cmiHideConnectLine.Click += new RoutedEventHandler(cmiHideConnectLine_Click);

            s_ContextMenu.Items.Add(cmiShowConnectLine);
            s_ContextMenu.Items.Add(cmiHideConnectLine);

            s_ContextMenu.Items.Add(new Separator());

            cmiDot = new MenuItem() { Header = "点线(_T)", Height = 20 };
            cmiDash = new MenuItem() { Header = "划线(_A)", Height = 20 };
            cmiDashDot = new MenuItem() { Header = "点划线(_H)", Height = 20 };
            cmiDashDotDot = new MenuItem() { Header = "点点划线(_D)", Height = 20 };
            cmiSolid = new MenuItem() { Header = "实线(_O)", Height = 20 };

            cmiDot.Click += new RoutedEventHandler(cmiDot_Click);
            cmiDash.Click += new RoutedEventHandler(cmiDash_Click);
            cmiDashDot.Click += new RoutedEventHandler(cmiDashDot_Click);
            cmiDashDotDot.Click += new RoutedEventHandler(cmiDashDotDot_Click);
            cmiSolid.Click += new RoutedEventHandler(cmiSolid_Click);

            s_ContextMenu.Items.Add(cmiDot);
            s_ContextMenu.Items.Add(cmiDash);
            s_ContextMenu.Items.Add(cmiDashDot);
            s_ContextMenu.Items.Add(cmiDashDotDot);
            s_ContextMenu.Items.Add(cmiSolid);

            s_ContextMenu.Items.Add(new Separator());

            MenuItem miSetXamlText = new MenuItem() { Header = "粘贴 Lunar Concept 页(_X)", };
            miSetXamlText.Click += miSetXamlText_Click;
            s_ContextMenu.Items.Add(miSetXamlText);

            MenuItem miClearXamlText = new MenuItem() { Header = "清除 Lunar Concept 页(_C)", };
            miClearXamlText.Click += MiClearXamlText_Click;
            s_ContextMenu.Items.Add(miClearXamlText);

            MenuItem miCopyXamlText = new MenuItem() { Header = "复制 Lunar Concept 页(_O)", };
            miCopyXamlText.Click += MiCopyXamlText_Click;
            s_ContextMenu.Items.Add(miCopyXamlText);

            defaultBitmap = new BitmapImage(new Uri("pack://application:,,,/LunarMind;component/Resources/Icons/Image.png"));
            errorBitmap = new BitmapImage(new Uri("pack://application:,,,/LunarMind;component/Resources/Icons/error.png"));

        }

        private static void MiCopyXamlText_Click(object sender, RoutedEventArgs e)
        {
            var mainSelPictureBox = Globals.MainWindow.SelectedPictureBox;

            var node = mainSelPictureBox.xmlData.SelectSingleNode("LunarConcept");
            if (node == null) return;

            Clipboard.SetData(DataFormats.UnicodeText, "<LunarMind.Xaml>" + node.OuterXml + "</LunarMind.Xaml>");
        }

        private static void MiClearXamlText_Click(object sender, RoutedEventArgs e)
        {
            PictureBox pBox = Globals.MainWindow.SelectedPictureBox;
            if (pBox == null)
            {
                MessageBox.Show("　　请先选中一个外置式图片框！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            var masterTitle = pBox.MasterTitle;
            if (masterTitle == null || masterTitle.ID == null || masterTitle.ID.Length <= 0)
            {
                MessageBox.Show("此图片构造异常。未传入它所在的标题，或所在标题的ID为空。无法继续设置其图像或图形。",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            string imgDataText = "";

            XmlNode imgNode = pBox.XmlData;

            string oldImgText = imgNode.InnerXml;

            var mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "清除图片框图像数据"
            };

            Action action = new Action(pBox.ID, -1,
                pBox.GetType().Name, "ImageBase64",
                oldImgText, imgDataText, ActionType.Property, masterTitle.ID);
            mi.Add(action);

            pBox.XmlData.InnerXml = imgDataText;
            pBox.BuildPictureBox();

            //添加到“撤销”列表。
            pBox.Editor.Do(mi);
            pBox.editor.IsModified = true;
            pBox.editor.RefreshTitleAndLinesLocation();
        }

        private static void EditLunarConceptProcess_Exited(object sender, EventArgs e)
        {
            //TODO: 将《Lunar Concept》编辑过后的Page Xml文件写入此PictureBox。

        }

        private static void MiSuperlargeIcon_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null) return;
            var pictureBox = Globals.MainWindow.SelectedPictureBox;

            if (pictureBox.mode == ImageMode.SuperLargeIcon) return;

            ModifingItem mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框呈现模式为：特大图标"
            };

            Action actMode = new Action(pictureBox.ID, -1, pictureBox.GetType().Name, "Mode",
                pictureBox.Mode.ToString(), ImageMode.SuperLargeIcon.ToString());
            pictureBox.Mode = ImageMode.SuperLargeIcon;
            mi.Add(actMode);

            if (mi.ModifiedPropertyAndValues.Count > 0)
            {
                Globals.MainWindow.Do(mi);
                Globals.MainWindow.IsModified = true;
                //Globals.MainWindow.RefreshTitleAndLinesLocation();//无必要
            }
        }

        private static void MiLargeIcon_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null) return;
            var pictureBox = Globals.MainWindow.SelectedPictureBox;

            if (pictureBox.mode == ImageMode.LargeIcon) return;

            ModifingItem mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框呈现模式为：大图标"
            };

            Action actMode = new Action(pictureBox.ID, -1, pictureBox.GetType().Name, "Mode",
                pictureBox.Mode.ToString(), ImageMode.LargeIcon.ToString());
            pictureBox.Mode = ImageMode.LargeIcon;
            mi.Add(actMode);

            if (mi.ModifiedPropertyAndValues.Count > 0)
            {
                Globals.MainWindow.Do(mi);
                Globals.MainWindow.IsModified = true;
                //Globals.MainWindow.RefreshTitleAndLinesLocation();//无必要
            }
        }

        private static void MiSmallIcon_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null) return;
            var pictureBox = Globals.MainWindow.SelectedPictureBox;

            if (pictureBox.mode == ImageMode.SmallIcon) return;

            ModifingItem mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框呈现模式为：小图标"
            };

            Action actMode = new Action(pictureBox.ID, -1, pictureBox.GetType().Name, "Mode",
                pictureBox.Mode.ToString(), ImageMode.SmallIcon.ToString());
            pictureBox.Mode = ImageMode.SmallIcon;
            mi.Add(actMode);

            if (mi.ModifiedPropertyAndValues.Count > 0)
            {
                Globals.MainWindow.Do(mi);
                Globals.MainWindow.IsModified = true;
                //Globals.MainWindow.RefreshTitleAndLinesLocation();//无必要
            }
        }

        private static void miSetXamlText_Click(object sender, RoutedEventArgs e)
        {
            PasteContextXamlToPictureBox();
        }

        public static void PasteContextXamlToPictureBox()
        {
            PictureBox pBox = Globals.MainWindow.SelectedPictureBox;
            if (pBox == null)
            {
                MessageBox.Show("　　请先选中一个外置式图片框！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            var masterTitle = pBox.MasterTitle;
            if (masterTitle == null || masterTitle.ID == null || masterTitle.ID.Length <= 0)
            {
                MessageBox.Show("此图片构造异常。未传入它所在的标题，或所在标题的ID为空。无法继续设置其图像或图形。",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            string imgDataText = Clipboard.GetText(TextDataFormat.UnicodeText);

            imgDataText = imgDataText.Replace("<LunarMind.Xaml>", "").Replace("</LunarMind.Xaml>", "");
            
            XmlNode imgNode = pBox.XmlData;

            string oldImgText = imgNode.InnerXml;

            var mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框图像数据",
            };

            Action action = new Action(pBox.ID, -1,
                pBox.GetType().Name, "ImageBase64",
                oldImgText, imgDataText, ActionType.Property, masterTitle.ID);
            mi.Add(action);

            pBox.XmlData.InnerXml = imgDataText;
            pBox.BuildPictureBox();

            //添加到“撤销”列表。
            pBox.Editor.Do(mi);
            pBox.editor.IsModified = true;
            pBox.editor.RefreshTitleAndLinesLocation();
        }

        static void miImageTitle_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox == null) return;

            var picbox = Globals.MainWindow.SelectedPictureBox;

            Dialogs.InputWindow iw = new Dialogs.InputWindow(Globals.MainWindow,
                "请输入图像标题（此标题将在演示图像时呈现在演示窗口顶部）：", picbox.Title, Globals.AppName, null, false);
            if (iw.ShowDialog() != true) return;

            string newTitleText = iw.InputedText;

            ModifingItem mi = new ModifingItem()
            {
                IsNeedRefreshTitleAndLinesLocation = true,
                ModifingName = "设置图片框的标题文本"
            };

            Action actMode = new Action(picbox.ID, -1, picbox.GetType().Name, "Title",
                picbox.Title, newTitleText);
            picbox.Title = newTitleText;
            mi.Add(actMode);

            if (mi.ModifiedPropertyAndValues.Count > 0)
            {
                Globals.MainWindow.Do(mi);
                Globals.MainWindow.IsModified = true;
                //Globals.MainWindow.RefreshTitleAndLinesLocation();
            }
        }

        static void miPresentateImage_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedPictureBox != null)
            {
                Globals.MainWindow.SelectedPictureBox.PresentateImage();
            }
        }

        public static BitmapImage defaultBitmap;

        public static System.Windows.Media.Imaging.BitmapImage errorBitmap;

        static void contextMenu_Opened(object sender, RoutedEventArgs e)
        {
            bool hideConnectLine;
            if (Globals.MainWindow.SelectedPictureBox == null)
            {
                hideConnectLine = true;
            }
            else
            {
                hideConnectLine = Globals.MainWindow.SelectedPictureBox.HideConnectLine;

                miDefaultMode.IsChecked = false;
                miSmallIconMode.IsChecked = false;
                miMediumIconMode.IsChecked = false;
                miLargeIconMode.IsChecked = false;
                miSuperlargeIconMode.IsChecked = false;

                switch (Globals.MainWindow.SelectedPictureBox.mode)
                {
                    case ImageMode.SmallIcon:
                        {
                            miSmallIconMode.IsChecked = true;
                            break;
                        }
                    case ImageMode.Icon:
                        {
                            miMediumIconMode.IsChecked = true;
                            break;
                        }
                    case ImageMode.LargeIcon:
                        {
                            miLargeIconMode.IsChecked = true;
                            break;
                        }
                    case ImageMode.SuperLargeIcon:
                        {
                            miSuperlargeIconMode.IsChecked = true;
                            break;
                        }
                    default:
                        {
                            miDefaultMode.IsChecked = true;
                            break;
                        }
                }
            }

            cmiShowConnectLine.IsEnabled = hideConnectLine;
            cmiHideConnectLine.IsEnabled = !hideConnectLine;

            cmiDash.IsEnabled =
            cmiDashDot.IsEnabled =
            cmiDashDotDot.IsEnabled =
            cmiDot.IsEnabled =
            cmiSolid.IsEnabled = !hideConnectLine;

            if (!hideConnectLine)
            {
                Image imgLine = new Image();
                imgLine.Width = imgLine.Height = 16;
                imgLine.Source = new BitmapImage(new Uri("pack://Application:,,,/LunarMind;component/Resources/Icons/Selected.png"));

                switch (Globals.MainWindow.SelectedPictureBox.LineDash)
                {
                    case LineDashType.DashType.Dash:
                        {
                            cmiDash.Icon = imgLine;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.DashDot:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = imgLine;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.DashDotDot:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = imgLine;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.Dot:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = imgLine;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.Solid:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = imgLine;
                            break;
                        }
                }
            }
            else
            {
                cmiDash.Icon = null;
                cmiDashDot.Icon = null;
                cmiDashDotDot.Icon = null;
                cmiDot.Icon = null;
                cmiSolid.Icon = null;
            }
        }

        static void cmiSolid_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.Solid);
        }

        static void cmiDashDotDot_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.DashDotDot);
        }

        static void cmiDashDot_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.DashDot);
        }

        static void cmiDash_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.Dash);
        }

        static void cmiDot_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.Dot);
        }

        private static void SetLineDash(LineDashType.DashType newDashType)
        {
            if (Globals.MainWindow.SelectedPictureBox != null)
            {
                PictureBox c = Globals.MainWindow.SelectedPictureBox;
                if (c.LineDash != newDashType)
                {
                    ModifingItem mi = new ModifingItem() { ModifingName = "设置图片框文本块连接线线型" };
                    Action actDashType = new Action(c.id, -1, c.GetType().Name, "LineDash",
                        c.LineDash.ToString(), newDashType.ToString());

                    c.LineDash = newDashType;

                    mi.Add(actDashType);
                    Globals.MainWindow.Do(mi);
                    Globals.MainWindow.IsModified = true;
                }
            }
        }

        public void BuildPictureBox()
        {
            if (this.xmlData == null)
            {
                mainImage.Width = PictureBox.defaultBitmap.PixelWidth;
                mainImage.Height = PictureBox.defaultBitmap.PixelHeight;
                mainImage.Source = PictureBox.defaultBitmap;
                if (this.baseViewBox.Child != mainImage) this.baseViewBox.Child = mainImage;
                return;
            }

            try
            {

                XmlAttribute attrID = this.xmlData.GetAttribute("ID");
                if (attrID != null && attrID.Value.Length > 0)
                {
                    this.id = attrID.Value;
                }
                else
                {
                    RebuildANewID();
                }

                XmlAttribute attrMode = this.xmlData.GetAttribute("Mode");
                if (attrMode != null)
                {
                    this.mode = (ImageMode)Enum.Parse(typeof(ImageMode), attrMode.Value);
                }

                #region 读取图片数据。
                XmlNode imgNode = this.XmlData;

                //图片可能无数据。
                string imgDataText = imgNode.InnerXml;
                //要考虑XamlElement故改用InnerXml，原来只需要InnerText即可。2014年3月24日

                try
                {
                    BitmapImage bmp = new BitmapImage();

                    if (imgDataText != null && IsBase64(imgDataText))
                    {
                        byte[] b = Convert.FromBase64String(imgDataText);
                        bmp.BeginInit();
                        bmp.StreamSource = new MemoryStream(b);
                        bmp.EndInit();

                        mainImage.Source = bmp;
                        if (this.baseViewBox.Child != this.mainImage)
                        {
                            this.baseViewBox.Child = this.mainImage;
                        }
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(imgDataText))
                        {
                            mainImage.Source = defaultBitmap;
                            if (this.baseViewBox.Child != mainImage)
                            {
                                this.baseViewBox.Child = mainImage;
                            }
                        }
                        else
                        {
                            //bmp = TitleImage.defaultBitmap;//必为尝试按Xaml解析。
                            TryToLoadXamlElement(imgDataText);
                        }
                    }
                }
                catch (FormatException)
                {
                    TryToLoadXamlElement(imgDataText);
                }

                this.RefreshMode();

                #endregion

                XmlAttribute attrLocation = this.xmlData.GetAttribute("Location");
                if (attrLocation != null)
                {
                    this.location = Point.Parse(attrLocation.Value);
                }

                XmlAttribute attrBorderColor = this.xmlData.GetAttribute("BorderColor");
                if (attrBorderColor != null)
                {
                    this.borderColor = ColorPicker.GetBrushByName(attrBorderColor.Value);
                    this.connectLine.Stroke = this.borderColor;
                }

                XmlAttribute attrHideConnectLine = this.xmlData.GetAttribute("HideConnectLine");
                if (attrHideConnectLine != null)
                {
                    this.hideConnectLine = bool.Parse(attrHideConnectLine.Value);
                }

                XmlAttribute attrRotateAngle = this.xmlData.GetAttribute("RotateAngle");
                if (attrRotateAngle != null)
                {
                    this.rotateAngle = double.Parse(attrRotateAngle.Value);
                    RefreshRotateAngle();
                }

                XmlAttribute attrLineDash = this.xmlData.GetAttribute("LineDash");
                if (attrLineDash != null)
                {
                    lineDash = (LineDashType.DashType)Enum.Parse(typeof(LineDashType.DashType), attrLineDash.Value);
                    RefreshDashType();
                }

                RefreshLoaction();
            }
            catch (Exception ex)
            {
                Dialogs.LunarMsgBox.MsgBoxShow(Globals.AppName,
                   "图片框构造时出现异常。异常信息如下：\r\n", ex.Message,
                   ex.StackTrace, MessageBoxButton.OK, MessageBoxImage.Warning, null, MessageBoxResult.OK,
                   Globals.MainWindow);
                return;
            }
        }


        private FrameworkElement xamlElement;
        /// <summary>
        /// [只读]与MainImage不同时出现。当不存在Base64文本形式存储的图像数据时，尝试按Xaml来解析。
        /// </summary>
        public FrameworkElement XamlElement
        {
            get { return xamlElement; }
        }


        private void TryToLoadXamlElement(string xamltext)
        {
            if (string.IsNullOrEmpty(xamltext))
            {
                this.mainImage.Source = PictureBox.errorBitmap;
                return;
            }

            if (xamltext.StartsWith("<LunarConcept>") && xamltext.EndsWith("</LunarConcept>"))
            {
                TryLoadConcept();
                return;
            }

            byte[] array = System.Text.Encoding.UTF8.GetBytes(xamltext);

            try
            {
                using (var stream = new System.IO.MemoryStream(array))
                {
                    this.xamlElement = System.Windows.Markup.XamlReader.Load(stream) as FrameworkElement;

                    this.baseViewBox.Child = this.xamlElement;

                    this.xamlElement.SizeChanged += xamlElement_SizeChanged;
                    this.xamlElement.MouseDown += this.mainImage_MouseDown;
                    this.xamlElement.PreviewMouseLeftButtonDown += this.baseBorder_PreviewMouseLeftButtonDown;
                    this.xamlElement.PreviewMouseRightButtonDown += this.mainImage_PreviewMouseRightButtonDown;
                    this.xamlElement.MouseLeftButtonUp += this.mainImage_MouseLeftButtonUp;
                }
            }
            catch (Exception)
            {
                if (this.baseViewBox.Child != this.mainImage)
                    this.baseViewBox.Child = this.mainImage;
                this.mainImage.Source = TitleImage.errorBitmap;
            }
        }

        private void TryLoadConcept()
        {
            PageEditorReader per = new PageEditorReader();
            var conceptNode = this.xmlData.SelectSingleNode(XmlTags.LunarConceptTag);
            per.XmlData = conceptNode.SelectSingleNode(XmlTags.PageTag);
            //per.Build();//设置XmlData属性值时会自动调用。

            this.baseViewBox.Child = per;
        }

        void mainImage_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            //会清除所有对标题的选取。
            this.IsSelected = true;

            //这个属性会执行清除选取状态的操作。
            editor.SelectedPictureBox = this;
            e.Handled = true;

            this.ContextMenu.IsOpen = true;
        }


        void mainImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (this.MasterTitle != null)
            {
                this.MasterTitle.DropOrLinkTitle();
            }
        }


        void xamlElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            //这种不在Title内部的图片，不需要重排布局。
            //if (editor != null) editor.RefreshTitleAndLinesLocation();
        }


        private static readonly HashSet<char> h = new HashSet<char>(){
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
            '='};

        public static bool IsBase64(string s)
        {
            if (string.IsNullOrEmpty(s))
                return false;
            else if (s.Any(c => !h.Contains(c)))
                return false;

            return true;
            //转为图像数据时会自动再转，不需要重复。
            //try
            //{
            //    Convert.FromBase64String(s);
            //    return true;
            //}
            //catch (FormatException)
            //{
            //    return false;
            //}
        }


        private Brush borderColor = Brushes.SkyBlue;

        public Brush BorderColor
        {
            get { return borderColor; }
            set
            {
                borderColor = value;
                this.connectLine.Stroke = borderColor;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("BorderColor", ColorPicker.GetBrushName(value));
                }
                this.borderAdorner.InvalidateVisual();
            }
        }

        private MainWindow editor;

        public MainWindow Editor
        {
            get { return editor; }
            set { editor = value; }
        }

        private string masterTitleID = null;

        /// <summary>
        /// 主标题的ID.
        /// </summary>
        public string MasterTitleID
        {
            get { return masterTitleID; }
            set
            {
                masterTitleID = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("MasterTitleID", value);
                }

                RefreshLoaction();
            }
        }

        private Title masterTitle;

        /// <summary>
        /// 主标题。
        /// </summary>
        public Title MasterTitle
        {
            get
            {
                if (masterTitle != null) return masterTitle;

                if (editor == null) return null;

                foreach (UIElement ue in editor.mainCanvas.Children)
                {
                    Title t = ue as Title;
                    if (t == null) continue;

                    if (t.ID == masterTitleID) return t;
                }

                return null;
            }
        }


        internal void LoadImageFromFile(ModifingItem mi = null, string fileFullname = null)
        {
            if (masterTitle == null || masterTitle.ID == null || masterTitle.ID.Length <= 0)
            {
                MessageBox.Show("此图片框构造异常。未传入它所在的标题，或所在标题的ID为空。无法继续设置其图像。",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            string filename = "";

            if (fileFullname == null)
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Multiselect = false;
                ofd.Title = Globals.AppName + "——请选择需要的图片：";
                ofd.Filter = "支持的所有图片格式(*.bmp;*.gif;*.jpg;*.jpeg;*.png;*.tiff)|*.bmp;*.gif;*.jpg;*.jpeg;*.png;*.tiff|" +
                    "PNG或JPEG图片(*.png;*.jpg;*.jpeg)|*.png;*.jpg;*.jpeg|" +
                    "联合图像专家组格式(*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
                    "图形交换格式(*.gif)|*.gif|" +
                    "W3C 可移植网络图形(*png)|*png|" +
                    "标题图像文件(*.tiff)|*.tiff";

                if (ofd.ShowDialog() != true) return;

                filename = ofd.FileName;
            }
            else
            {
                filename = fileFullname;
            }

            System.IO.FileInfo fileInfo = new FileInfo(filename);
            if (fileInfo.Exists == false)
            {
                System.Windows.MessageBox.Show("文件不存在！", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (fileInfo.Length <= 2097152)//将图片限制在2MB以内
            {
                System.Drawing.Image fileImg = System.Drawing.Image.FromFile(filename);
                using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
                {
                    try
                    {
                        if (fileInfo.Extension.ToLower() == ".png")
                        {
                            fileImg.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
                        }
                        else if (fileInfo.Extension.ToLower() == ".jpg" || fileInfo.Extension.ToLower() == ".jpeg")
                        {
                            fileImg.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
                        }
                        else if (fileInfo.Extension.ToLower() == ".gif")
                        {
                            fileImg.Save(stream, System.Drawing.Imaging.ImageFormat.Gif);
                        }
                        else if (fileInfo.Extension.ToLower() == ".tiff")
                        {
                            fileImg.Save(stream, System.Drawing.Imaging.ImageFormat.Tiff);
                        }
                        else if (fileInfo.Extension.ToLower() == ".bmp")
                        {
                            fileImg.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
                        }
                        else
                        {
                            return;//不能识别的文件格式。
                        }

                        byte[] b = stream.GetBuffer();
                        string imgDataText = Convert.ToBase64String(b);

                        XmlNode imgNode = this.XmlData;

                        string oldImgText = imgNode.InnerText;
                        imgNode.InnerText = imgDataText;

                        //XmlData.SetAttribute("Width", fileImg.Width.ToString());
                        //XmlData.SetAttribute("Height", fileImg.Height.ToString());
                        //mainImage.Width = fileImg.Width;
                        //mainImage.Height = fileImg.Height;

                        //if (fileImg.Width > 200 || fileImg.Height > 200)
                        //{
                        //标题中强迫尺寸过大的图像以图标模式呈现——除非用户手动更改模式。
                        //但在图片框中不需要如此。因为它不影响树的布局。

                        //var result = MessageBox.Show("　　此图像高度或宽度大于200，要以【图标模式】呈现吗？", Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Question);
                        //if (result == MessageBoxResult.Yes)
                        //{

                        //if (this.Mode != ImageMode.Icon)
                        //{
                        //    Action actMode = new Action(this.ID, -1, this.GetType().Name, "Mode", this.Mode.ToString(), ImageMode.Icon.ToString());
                        //    this.Mode = ImageMode.Icon;
                        //    mi.Add(actMode);
                        //}
                        //}
                        //}

                        mainImage.Source = new BitmapImage(new Uri(filename));
                        if (this.baseViewBox.Child != mainImage)
                        {
                            this.baseViewBox.Child = mainImage;
                        }

                        #region 准备“撤销”与“重做”数据。
                        if (mi == null)
                        {
                            mi = new ModifingItem()
                            {
                                IsNeedRefreshTitleAndLinesLocation = true,
                                ModifingName = "设置标题图像数据"
                            };
                        }

                        Action action = new Action(this.ID, -1,
                            this.GetType().Name, "ImageBase64",
                            oldImgText, imgDataText, ActionType.Property, masterTitle.ID);
                        mi.Add(action);
                        #endregion

                        this.RefreshMode();

                        //添加到“撤销”列表。
                        Editor.Do(mi);

                        editor.IsModified = true;
                        editor.RefreshTitleAndLinesLocation();
                    }
                    catch (System.Runtime.InteropServices.ExternalException ex)
                    {
                        Dialogs.LunarMsgBox.MsgBoxShow(
                            Globals.AppName,
                            "未能载入图片文件。",
                            "该图像以错误的图像格式后缀名保存！\r\n" + ex.Message,
                            ex.StackTrace, MessageBoxButton.OK, MessageBoxImage.Warning);
                    }
                }
                fileImg.Dispose();
            }
            else
            {
                Dialogs.LunarMsgBox.MsgBoxShow(
                     Globals.AppName,
                     "图片文件太大。",
                     "为防止文档体积过分庞大，本图片框只支持文件尺寸在 500KB 以下的图片！",
                     "请将图片加工一下或另选一张图片。",
                     MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        private Point location = new Point(-100, 100);//默认在主标题的左下角。

        /// <summary>
        /// 与主标题的相对位置。
        /// </summary>
        public Point Location
        {
            get { return location; }
            set
            {
                location = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("Location", value.ToString());
                }
                RefreshLoaction();
            }
        }

        /// <summary>
        /// 一次公式级的撤销操作。
        /// </summary>
        /// <param name="action">一次撤销或重做可以涉及到多个公式（因而包含多次公式级的撤销或重做）。</param>
        public virtual void Undo(Action action)
        {
            if (action != null)
            {
                SetProperty(action.PropertyOrActionTypeName, action.OldValue);
            }
        }

        /// <summary>
        /// 一次公式级的重做操作。
        /// </summary>
        /// <param name="action"></param>
        public virtual void Redo(Action action)
        {
            if (action != null)
            {
                SetProperty(action.PropertyOrActionTypeName, action.NewValue);
            }
        }

        public virtual void SetProperty(string propertyName, string value)
        {
            switch (propertyName)
            {
                case "Location":
                    {
                        this.Location = Point.Parse(value);
                        RefreshLoaction();
                        break;
                    }
                case "BorderColor":
                    {
                        this.BorderColor = ColorPicker.GetBrushByName(value);
                        break;
                    }
                case "HideConnectLine":
                    {
                        this.HideConnectLine = bool.Parse(value); break;
                    }
                case "RotateAngle":
                    {
                        this.RotateAngle = double.Parse(value); break;
                    }
                case "LineDash":
                    {
                        this.LineDash = (LineDashType.DashType)Enum.Parse(typeof(LineDashType.DashType), value);
                        break;
                    }
                case "ImageBase64":
                    {
                        this.xmlData.InnerText = value;
                        BuildPictureBox();
                        break;
                    }
                case "Mode":
                    {
                        this.Mode = (ImageMode)Enum.Parse(typeof(ImageMode), value);
                        break;
                    }
                case "Title":
                    {
                        this.Title = value; break;
                    }
            }
        }
    }
}
